package com.lhg.video.controller;

import com.lhg.common.page.ResultInfo;
import com.lhg.common.util.FileInfo;
import com.lhg.common.util.MD5Utils;
import org.springframework.stereotype.Controller;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author fzc
 * @date 2018/10/12 15:56
 */
@Controller
@RequestMapping("/video")
public class VideoController {

    private final String fileParentPath = "/WEB-INF/upload/video";

    /**
     * 获取视频列表
     *
     * @param request
     * @return
     */
    @RequestMapping("/list")
    @ResponseBody
    public ResultInfo list(HttpServletRequest request) {
        String parentPath = request.getServletContext().getRealPath(fileParentPath);
        //首先获取video目录中的所有文件夹和文件，然后，货物文件夹中的子文件夹和文件
        //文件对象信息：文件路径，文件名，子文件夹
        parentPath = "E:\\IT视频";
        return ResultInfo.success(getAllFileInfo(parentPath));
    }

    /**
     * 获取这个文件夹下所有一级资源
     *
     * @param parentPath
     * @return
     */
    private List<FileInfo> getAllFileInfo(String parentPath) {
        //传入父目录路径
        //获取所有子一级目录和文件
        //子一级目录再次调用此方法
        File parentfile = new File(parentPath);
        File[] subFiles = null;
        if (parentfile.isDirectory()) {
            subFiles = parentfile.listFiles();
        }
        List<FileInfo> subFileInfoList = new ArrayList<>();
        FileInfo subFileInfo = null;
        if (subFiles != null) {
            for (int i = 0; i < subFiles.length; i++) {
                File subFile = subFiles[i];
                subFileInfo = new FileInfo();
                subFileInfo.setId(MD5Utils.md5(subFile.getAbsolutePath()));
                subFileInfo.setPid(MD5Utils.md5(parentfile.getAbsolutePath()));
                String fileName = subFile.getName();
                subFileInfo.setName(fileName);
                String url = "";
                if (fileName.toLowerCase().endsWith(".mp4") || fileName.toLowerCase().endsWith(".ogg") || fileName.toLowerCase().endsWith(".webm")) {//视频
                    /*h5播放器支持视频格式：
                        MP4 = MPEG 4文件使用 H264 视频编解码器和AAC音频编解码器
                        WebM = WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器
                        Ogg = Ogg 文件使用 Theora 视频编解码器和 Vorbis音频编解码器*/
                    url = "/video/play?fileUrl=" + Base64Utils.encodeToString(subFile.getAbsolutePath().getBytes()).replaceAll("\\+", "%2B");
                }
                subFileInfo.setUrl(url);
                subFileInfo.setFile(subFile.isFile());
                if (subFile.isDirectory()) {
                    subFileInfo.setChildren(getAllFileInfo(subFile.getAbsolutePath()));
                } else {
                    subFileInfo.setChildren(new ArrayList<>());
                }
                subFileInfoList.add(subFileInfo);
            }
        }
        return subFileInfoList;
    }

    /**
     * 播放视频
     *
     * @param request
     * @param response
     */
    @RequestMapping("/play")
    public void play(HttpServletRequest request, HttpServletResponse response, String fileUrl) {
        fileUrl = Base64Utils.decodeFromString(fileUrl).toString();
        response.reset();//清空缓存
        String fileName = "个人原因未打卡";
        response.setContentType("video/mp4");//正文类型
        response.setHeader("Accept-Ranges", "bytes");
        response.setHeader("Last-Modified", new Date().toString());
        response.setHeader("ETag", fileName);
        String requestRange = request.getHeader("Range");
        int start = 0, end = 0;
        if (requestRange != null && requestRange.startsWith("bytes=")) {
            String[] values = requestRange.split("=")[1].split("-");
            start = Integer.parseInt(values[0]);
            if (values.length > 1) {
                end = Integer.parseInt(values[1]);
            }
        }
        int requestSize = 0;
        if (end != 0 && end > start) {
            requestSize = end - start + 1;
        } else {
            requestSize = Integer.MAX_VALUE;
        }

        File file = new File(fileUrl);
        RandomAccessFile randomFile = null;//只读模式
        try {
            randomFile = new RandomAccessFile(file, "r");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        setResponse(response, randomFile, requestRange);
        //输出
        ServletOutputStream out = null;
        int needSize = requestSize;
        try {
            out = response.getOutputStream();
            randomFile.seek(start);
            byte[] buffer = new byte[4096];
            while (needSize > 0) {
                int len = randomFile.read(buffer);
                if (needSize < buffer.length) {
                    out.write(buffer, 0, needSize);
                } else {
                    out.write(buffer, 0, len);
                    if (len < buffer.length) {
                        break;
                    }
                }
                needSize -= buffer.length;
            }
        } catch (IOException e) {
            //e.printStackTrace();
        } finally {
            try {
                randomFile.close();
                out.close();
            } catch (IOException e) {
                //e.printStackTrace();
            }
        }
    }

    /**
     * 设置content-length,content-range
     *
     * @param response
     * @param randomFile
     * @param requestRange
     */
    private void setResponse(HttpServletResponse response, RandomAccessFile randomFile, String requestRange) {
        long fileLength = 0;// 记录文件大小
        long requestStart = 0;
        long requestEnd = 0;

        try {
            fileLength = randomFile.length();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //第一次请求只返回content length来让客户端请求多次实际数据
        if (requestRange == null) {
            response.setHeader("Content-length", fileLength + "");
        } else {
            //以后的多次以断点续传的方式来返回视频数据
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
            String[] ranges = requestRange.split("=");
            if (ranges.length > 1) {
                String[] rangeDatas = ranges[1].split("-");
                requestStart = Integer.parseInt(rangeDatas[0]);
                if (rangeDatas.length > 1) {
                    requestEnd = Integer.parseInt(rangeDatas[1]);
                }
            }
            long length = 0;
            if (requestEnd > 0) {
                length = requestEnd - requestStart + 1;
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + fileLength);
            } else {
                length = fileLength - requestStart;
                response.setHeader("Content-length", "" + length);
                response.setHeader("Content-Range", "bytes " + requestStart + "-" + (fileLength - 1) + "/" + fileLength);
            }
        }

    }

}